package ui;

import graph.GraphFile;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import util.BFS;

/**
 * Graph viewer tool for performing demo. Does BFS to find path from one article to another.
 * 
 * @author Jonathan
 * 
 */
public class GraphViewer extends JPanel implements ActionListener, GraphViewerConstants
{
    protected JLabel actionLabel;
    protected JTextArea textArea;
    protected JButton submitTitleButton, submitNumButton;
    protected JTextField startPageNumTextField, endPageTitleTextField;
    private GraphFile gf;
    private JTextField startPageTitleTextField;
    private JTextField endPageNumTextField;

    public GraphViewer()
    {

	setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

	// Starting page fields
	startPageTitleTextField = new JTextField(20);

	JLabel startPageTitleLabel = new JLabel("Starting page title: ");
	startPageTitleLabel.setLabelFor(startPageTitleTextField);

	startPageNumTextField = new JTextField(10);

	JLabel startPageNumLabel = new JLabel("Starting page number: ");
	startPageNumLabel.setLabelFor(startPageNumTextField);

	// Ending page fields
	endPageTitleTextField = new JTextField(20);
	endPageTitleTextField.setName(PAGE_TITLE);

	JLabel endPageTitleLabel = new JLabel("Ending page title: ");
	endPageTitleLabel.setLabelFor(endPageTitleTextField);

	endPageNumTextField = new JTextField(10);
	endPageNumTextField.setName(PAGE_NUM);

	JLabel endPageNumLabel = new JLabel("Ending page number: ");
	endPageNumLabel.setLabelFor(endPageNumTextField);

	// Buttons
	submitNumButton = new JButton("Submit Numbers");
	submitNumButton.addActionListener(this);
	submitNumButton.setActionCommand("submit_number");
	submitTitleButton = new JButton("Submit Titles");
	submitTitleButton.addActionListener(this);
	submitTitleButton.setActionCommand("submit_title");

	submitNumButton.setEnabled(false);
	submitTitleButton.setEnabled(false);

	actionLabel = new JLabel();
	actionLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));

	JPanel titleControlsPane = new JPanel();
	JPanel numControlsPane = new JPanel();

	GridBagLayout gridbag = new GridBagLayout();
	GridBagConstraints c = new GridBagConstraints();
	c.gridwidth = GridBagConstraints.REMAINDER; // last
	c.anchor = GridBagConstraints.WEST;
	c.weightx = 1.0;

	titleControlsPane.setLayout(gridbag);
	numControlsPane.setLayout(gridbag);

	JLabel[] labels = { startPageTitleLabel, endPageTitleLabel };
	JTextField[] textFields = { startPageTitleTextField, endPageTitleTextField };

	JLabel[] nlabels = { startPageNumLabel, endPageNumLabel };
	JTextField[] ntextFields = { startPageNumTextField, endPageNumTextField };

	addLabelTextRows(labels, textFields, gridbag, titleControlsPane);
	addLabelTextRows(nlabels, ntextFields, gridbag, numControlsPane);

	titleControlsPane.add(actionLabel, c);
	titleControlsPane.add(submitTitleButton, c);
	numControlsPane.add(actionLabel, c);
	numControlsPane.add(submitNumButton, c);

	titleControlsPane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Search by title"), BorderFactory.createEmptyBorder(5, 5, 5, 5)));
	numControlsPane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Search by page number"), BorderFactory.createEmptyBorder(5, 5, 5, 5)));

	textArea = new JTextArea();
	textArea.setEditable(false);
	textArea.setLineWrap(true);
	textArea.setWrapStyleWord(true);
	JScrollPane areaScrollPane = new JScrollPane(textArea);
	areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
	areaScrollPane.setPreferredSize(new Dimension(250, 250));

	JPanel leftPane = new JPanel();
	leftPane.setLayout(new BoxLayout(leftPane, BoxLayout.Y_AXIS));
	leftPane.add(titleControlsPane);
	leftPane.add(numControlsPane);

	JPanel rightPane = new JPanel(new GridLayout(1, 0));
	rightPane.add(areaScrollPane);
	rightPane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Output"), BorderFactory.createEmptyBorder(5, 5, 5, 5)));

	add(leftPane);
	add(rightPane);

	new Thread()
	{
	    public void run()
	    {
		textArea.append("Loading graph...\n");
		gf = new GraphFile(false);
		textArea.append("Graph loaded.\n");
		submitNumButton.setEnabled(true);
		submitTitleButton.setEnabled(true);
	    }
	}.start();
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
	if ("submit_number".equals(e.getActionCommand()))
	{
	    try
	    {
		String start = startPageNumTextField.getText();
		final int startPage = Integer.parseInt(start);

		String end = endPageNumTextField.getText();
		final int endPage = Integer.parseInt(end);

		new Thread()
		{
		    public void run()
		    {

			submitNumButton.setEnabled(false);
			submitTitleButton.setEnabled(false);
			textArea.append("Running BFS Traversal... \n");
			LinkedList<Integer> lli = BFS.findPath(gf, startPage, endPage);
			textArea.append("Path found (" + lli.size() + "): \n");
			for (int y : lli)
			    textArea.append(" >> " + gf.getPageName(y) + "\n");
			textArea.append("\n");

			submitNumButton.setEnabled(true);
			submitTitleButton.setEnabled(true);
		    }

		}.start();

	    } catch (Exception ex)
	    {
		ex.printStackTrace();
	    }

	}
	else if ("submit_title".equals(e.getActionCommand()))
	{
	    try
	    {
		String start = startPageTitleTextField.getText();
		final int startPage = gf.getPageNum(start);

		String end = endPageTitleTextField.getText();
		final int endPage = gf.getPageNum(end);

		new Thread()
		{
		    public void run()
		    {
			submitNumButton.setEnabled(false);
			submitTitleButton.setEnabled(false);
			textArea.append("Running BFS Traversal... \n");
			LinkedList<Integer> lli = BFS.findPath(gf, startPage, endPage);
			textArea.append("Path found (" + lli.size() + "): \n");
			for (int y : lli)
			    textArea.append(" >> " + gf.getPageName(y) + "\n");
			textArea.append("\n");
			submitNumButton.setEnabled(true);
			submitTitleButton.setEnabled(true);
		    }

		}.start();
	    } catch (Exception ex)
	    {
		ex.printStackTrace();
	    }
	}
    }

    private void addLabelTextRows(JLabel[] labels, JTextField[] textFields, GridBagLayout gridbag,
	    Container container)
    {
	GridBagConstraints c = new GridBagConstraints();
	c.anchor = GridBagConstraints.EAST;
	int numLabels = labels.length;

	for (int i = 0; i < numLabels; i++)
	{
	    c.gridwidth = GridBagConstraints.RELATIVE; // next-to-last
	    c.fill = GridBagConstraints.NONE; // reset to default
	    c.weightx = 0.0; // reset to default
	    container.add(labels[i], c);

	    c.gridwidth = GridBagConstraints.REMAINDER; // end row
	    c.fill = GridBagConstraints.HORIZONTAL;
	    c.weightx = 1.0;
	    container.add(textFields[i], c);
	}
    }

    /**
     * Create the GUI and show it. For thread safety, this method should be invoked from the event dispatch thread.
     */
    private static void createAndShowGUI()
    {
	// Create and set up the window.
	JFrame frame = new JFrame("Graph Tracer");
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	// Add content to the window.
	frame.add(new GraphViewer());

	// Display the window.
	frame.pack();
	frame.setVisible(true);
    }

    public static void main(String[] args)
    {
	// Schedule a job for the event dispatching thread:
	// creating and showing this application's GUI.
	SwingUtilities.invokeLater(new Runnable()
	{
	    public void run()
	    {
		// Turn off metal's use of bold fonts
		UIManager.put("swing.boldMetal", Boolean.FALSE);
		createAndShowGUI();
	    }
	});
    }

}
